package com.sc.nft.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.sc.nft.annotation.UserLogin;
import com.sc.nft.annotation.WithoutSign;
import com.sc.nft.controller.request.*;
import com.sc.nft.dao.*;
import com.sc.nft.dto.BindPaySendSmsVO;
import com.sc.nft.dto.llian.LlRandomPwdDTO;
import com.sc.nft.dto.llian.OpenAccountNotifyDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.vo.GetPaySignVO;
import com.sc.nft.entity.vo.PwdElementVO;
import com.sc.nft.enums.AccountStatusEnum;
import com.sc.nft.enums.PayChannelEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.WalletChannelEnum;
import com.sc.nft.enums.llian.LlUploadFileTypeEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.LlPayHelper;
import com.sc.nft.pool.UserPool;
import com.sc.nft.service.PayOrderService;
import com.sc.nft.service.ScOrderSettleService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.BankCardUtil;
import com.sc.nft.wrapper.RequestWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/pay/llPay")
@Api(tags = "连连接口")
public class LlPayController {
    private final PayOrderService payOrderService;
    private final PayOrderDao payOrderDao;
    private final LlPayHelper llPayHelper;
    private final BankBindApplyDao bankBindApplyDao;
    private final UserBankCardDao userBankCardDao;
    private final WithdrawBankCardDao withdrawBankCardDao;
    private final SandWithdrawRecordDao sandWithdrawRecordDao;
    private final LlUserExtDao llUserExtDao;
    private final StaticDataDao staticDataDao;
    private final Redisson redisson;
    private final LlExchangePhoneDao llExchangePhoneDao;
    private final DaoCustomerOpenAccountDao openAccountDao;
    private final DaoAccountBankInfoDao bankInfoDao;
    private final DaoWithdrawRecordDao daoWithdrawRecordDao;
    private final LlModifyUserInfoDao llModifyUserInfoDao;
    private final ScOrderSettleService orderSettleService;


    public static final String SUCCESS = "Success";
    public static final String FAIL = "Fail";

    @ApiOperation(value = "连连开户", notes = "连连开户", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llOpenAccount", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> llOpenAccount(@RequestBody H5Request request) {
        UserInfo user = UserPool.getUser();
        RLock lock = redisson.getLock(RedisKeyEnum.OPEN_ACCOUNT_LOCK + user.getId().toString());
        try {
            boolean res = lock.tryLock(1, TimeUnit.SECONDS);
            if (res) {
                return Result.success(llPayHelper.openAccount(user, request.getIsWeb()));
            } else {
                return Result.fail(ErrorCode.LATER_TRY);
            }
        } catch (InterruptedException e) {
            return Result.fail("操作人数过多,请稍后再试");
        } finally {
            lock.unlock();
        }
    }

    @ApiOperation(value = "连连开户回调", notes = "连连开户回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/openAccountNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String openAccountNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连回调参数：{}", req);
        OpenAccountNotifyDTO dto = req.toJavaObject(OpenAccountNotifyDTO.class);
//        OpenAccountNotifyDTO dto = new OpenAccountNotifyDTO();
        llPayHelper.openAccountSuccess(dto.getTxn_seqno(), dto.getLinked_agrtno(), dto.getUser_status(), dto.getOid_userno(), dto.getRemark(), dto.getBasicInfo(), dto.getLinkedAcctInfo(), dto.getBasicInfo() != null ? dto.getBasicInfo().getReg_phone() : null);
        return SUCCESS;
    }

    @ApiOperation(value = "获取随机密码因子", notes = "获取随机密码因子", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getRandom", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<LlRandomPwdDTO> getRandom(@RequestBody @Valid LlGetRandomRequest request) {
        UserInfo user = UserPool.getUser();
        return Result.success(llPayHelper.getRandom(user, request.getType(), request.getAppType()));
    }

    @ApiOperation(value = "找回密码", notes = "找回密码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/findPwd", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<String> findPwd(@RequestBody LlBankCardRequest request) {
        UserInfo user = UserPool.getUser();
        if (!BankCardUtil.checkBankCard(request.getBankCard())) {
            return Result.fail(ErrorCode.BANK_CARD_ERROR);
        }

        return Result.success(llPayHelper.findPwd(user, request.getBankCard()).getString("token"));
    }


    @ApiOperation(value = "找回密码验证", notes = "找回密码验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/findPwdVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result findPwdVerify(@RequestBody @Valid LlFindPwdRequest request) {
        UserInfo user = UserPool.getUser();
        llPayHelper.pwdVerify(user, request.getToken(), request.getSmsCode(), request.getRandomKey(), request.getPwd());
        return Result.success();
    }


    @ApiOperation(value = "密码控件token", notes = "密码控件token", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/pwdElement", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<PwdElementVO> pwdElement(@RequestBody @Valid LlSceneRequest request) {
        UserInfo user = UserPool.getUser();
        return Result.success(llPayHelper.getPwdElement(user, request.getScene(), request.getAmount()));
    }


    @ApiOperation(value = "连连匿名绑卡回调", notes = "连连匿名绑卡回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/anonymousBindCardNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String anonymousBindCardNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连匿名绑卡回调参数：{}", req);
        BankBindApply bankBindApply = bankBindApplyDao.getByApplyNo(req.getString("txn_seqno"));
        if (ObjectUtil.isNotNull(bankBindApply) && bankBindApply.getChannel() == PayChannelEnum.LL_PAY) {
            UserBankCard userBankCard = userBankCardDao.getByBindId(bankBindApply.getId());
            if (ObjectUtil.isNotNull(userBankCard) && StrUtil.isBlank(userBankCard.getSandBid())) {
                userBankCard.setSandBid(req.getString("linked_agrtno"));
                userBankCard.updateById();
            }
        }
        return SUCCESS;
    }

    @ApiOperation(value = "连连匿名解绑回调", notes = "连连匿名解绑回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/unAnonymousBindCardNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String unAnonymousBindCardNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连匿名解绑回调：{}", req);
        return SUCCESS;
    }

    @ApiOperation(value = "个人绑卡", notes = "个人绑卡", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/bindCard", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result bindCard(@RequestBody @Valid BindBankCardRequest request) {
        UserInfo user = UserPool.getUser();
        if (StrUtil.isBlank(request.getPassword())) {
            return Result.fail("请输入交易密码");
        }
        if (StrUtil.isBlank(request.getRandomKey())) {
            return Result.fail("随机因子不能为空");
        }
        return Result.success(llPayHelper.bindCard(user, request.getCardNo(), request.getCertificateNo(), request.getName(), request.getPhoneNo(), request.getPassword(), request.getRandomKey()));
    }

    @ApiOperation(value = "个人绑卡验证", notes = "个人绑卡验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/bindCardVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result bindCardVerify(@RequestBody @Valid BindBankCardVerifyRequest request) {
        UserInfo user = UserPool.getUser();
        BankBindApply bankBindApply = bankBindApplyDao.getById(request.getId());
        if (ObjectUtil.isNull(bankBindApply) || bankBindApply.getUserId().longValue() != user.getId().longValue() || bankBindApply.getChannel() != PayChannelEnum.LL_PAY) {
            return Result.fail("未找到绑卡记录");
        }
        llPayHelper.bindCardVerify(user, bankBindApply, request.getSmsCode());
        return Result.success();
    }


    @ApiOperation(value = "申请换绑手机号", notes = "申请换绑手机号", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/exchangePhone", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<Long> exchangePhone(@RequestBody @Valid LlExchangePhoneRequest request) {
        if (StrUtil.equals(request.getNewPhone(), request.getOldPhone())) {
            return Result.fail("新旧手机号不能一致");
        }
        return Result.success(llPayHelper.changePhone(UserPool.getUser(), request.getOldPhone(), request.getNewPhone(), request.getPassword(), request.getRandomKey()));
    }

    @ApiOperation(value = "换绑手机号验证", notes = "换绑手机号验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/exchangePhoneVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<Long> exchangePhoneVerify(@RequestBody @Valid LlExchangePhoneVerifyRequest request) {

        llPayHelper.exchangePhoneVerify(UserPool.getUser(), request.getId(), request.getVerifyCode());
        return Result.success();
    }

    @ApiOperation(value = "连连绑卡支付发送短信", notes = "连连绑卡支付发送短信", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llBindPaySendSms", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BindPaySendSmsVO> llBindPaySendSms(@Valid @RequestBody BindPaySendSmsRequest request, HttpServletRequest httpServletRequest) {
        return Result.fail("请下载最新版本APP");
//        return Result.success(payOrderService.llBindPaySendSms(request.getBankCardId(), request.getOrderId(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest)));
    }


    @ApiOperation(value = "连连绑卡支付短信验证", notes = "连连绑卡支付短信验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llPayVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<GetPaySignVO> llPayVerify(@Valid @RequestBody BindPayRequest request, HttpServletRequest httpServletRequest) {
        return Result.fail("请下载最新版本APP");
//        UserInfo user = UserPool.getUser();
//        if(StrUtil.isBlank(request.getToken())){
//            return Result.fail("token不能为空");
//        }
//        payOrderService.llPayVerify(user,request.getId(),request.getToken(),request.getSmsCode());
//        return Result.success();
    }

    @ApiOperation(value = "连连绑卡支付发送短信（二级）", notes = "连连绑卡支付发送短信（二级）", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llBindPaySendSmsSecond", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BindPaySendSmsVO> llBindPaySendSmsSecond(@Valid @RequestBody BindPaySendSmsSecondRequest request, HttpServletRequest httpServletRequest) {
        return Result.fail("请下载最新版本APP");
//        BindPaySendSmsVO vo = payOrderService.llBindPaySendSmsSecond(request.getBankCardId(), request.getOrderIds(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest));
//        return Result.success(vo);
    }

    @ApiOperation(value = "连连绑卡支付发送短信（原石）", notes = "连连绑卡支付发送短信（原石）", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/llBindPaySendSmsRoughStone", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result<BindPaySendSmsVO> llBindPaySendSmsRoughStone(@Valid @RequestBody BindPaySendSmsRequest request, HttpServletRequest httpServletRequest) {
        return Result.fail("请下载最新版本APP");
//        return Result.success(payOrderService.llBindPaySendSmsByRoughStone(request.getBankCardId(), request.getOrderId(), UserPool.getUser(), ServletUtil.getClientIP(httpServletRequest)));
    }


    @ApiOperation(value = "提现验证", notes = "提现验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdrawVerify", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result withdrawVerify(@RequestBody @Valid BindBankCardVerifyRequest request) {
        UserInfo user = UserPool.getUser();
        SandWithdrawRecord withdrawRecord = sandWithdrawRecordDao.getById(request.getId());
        if (ObjectUtil.isNull(withdrawRecord) || withdrawRecord.getUserId().longValue() != user.getId().longValue() || withdrawRecord.getChannel() != WalletChannelEnum.LL) {
            return Result.fail("未找到提现记录");
        }
        llPayHelper.withdrawVerifySmsCode(user, withdrawRecord, request.getSmsCode());
        return Result.success();
    }

    @ApiOperation(value = "个人解绑卡", notes = "个人绑卡验证", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/unBindCard", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result unBindCard(@RequestBody @Valid LlUnBindRequest request) {
        UserInfo user = UserPool.getUser();
        WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(request.getId());
        if (ObjectUtil.isNull(withdrawBankCard) || withdrawBankCard.getStatus() == false || withdrawBankCard.getUserId().longValue() != user.getId().longValue() || withdrawBankCard.getChannel() != WalletChannelEnum.LL) {
            return Result.fail("未找到绑卡记录");
        }

        if (withdrawBankCard.getBindId().longValue() == 0L) {
            return Result.fail("默认卡不允许解绑");
        }

        llPayHelper.unBindCard(user, withdrawBankCard, request.getPwd(), request.getRandomKey());
        return Result.success();
    }


    @ApiOperation(value = "提现申请", notes = "提现申请", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdrawApply", produces = MediaType.APPLICATION_JSON_VALUE)
    @UserLogin
    public Result withdrawApply(@RequestBody @Valid LlWithdrawRequest request) {
        UserInfo user = UserPool.getUser();
        LlUserExt llUserExt = llUserExtDao.getByUserId(user.getId());
        Assert.isTrue(ObjectUtil.isNotNull(llUserExt) && llUserExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("连连支付尚未开户"));
        WithdrawBankCard withdrawBankCard = withdrawBankCardDao.getById(request.getWithdrawBankId());
        if (ObjectUtil.isNull(withdrawBankCard) || BooleanUtil.isFalse(withdrawBankCard.getStatus()) || withdrawBankCard.getUserId().longValue() != user.getId().longValue() || withdrawBankCard.getChannel() != WalletChannelEnum.LL) {
            return Result.fail("未找到银行卡");
        }
        String minimumWithdrawalAmountString = staticDataDao.getByType("minimum_withdrawal_amount").getValue();
        if (new BigDecimal(minimumWithdrawalAmountString).compareTo(request.getAmount()) > 0) {
            return Result.fail("提现金额不能小于" + minimumWithdrawalAmountString + "元");
        }
        return Result.success(llPayHelper.withdraw(user, llUserExt, withdrawBankCard, request.getAmount(), request.getPassword(), request.getRandomKey()));
    }

    @ApiOperation(value = "连连绑卡回调", notes = "连连绑卡回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/bindCardNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String bindCardNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连绑卡回调参数：{}", req);
        BankBindApply bankBindApply = bankBindApplyDao.getByApplyNo(req.getString("txn_seqno"));
        if (ObjectUtil.isNotNull(bankBindApply) && bankBindApply.getChannel() == PayChannelEnum.LL_PAY) {
            WithdrawBankCard userBankCard = withdrawBankCardDao.getByBindId(bankBindApply.getId());
            if (ObjectUtil.isNotNull(userBankCard) && StrUtil.isBlank(userBankCard.getRelatedCardNo())) {
                userBankCard.setRelatedCardNo(req.getString("linked_agrtno"));
                userBankCard.updateById();
            }
        }
        return SUCCESS;
    }

    @ApiOperation(value = "连连提现回调", notes = "连连提现回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/withdrawNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String withdrawNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连提现回调参数：{}", req);
        if (StrUtil.equals(req.getString("txn_status"), "TRADE_SUCCESS")) {
            sandWithdrawRecordDao.success(req.getJSONObject("orderInfo").getString("txn_seqno"));
        } else {
            sandWithdrawRecordDao.fail(req.getJSONObject("orderInfo").getString("txn_seqno"), req.getString("failure_reason"));

        }
        return SUCCESS;
    }


    @ApiOperation(value = "连连Dao提现回调", notes = "连连提现回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/daoWithdrawNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String daoWithdrawNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连提现回调参数：{}", req);
        if (StrUtil.equals(req.getString("txn_status"), "TRADE_SUCCESS")) {
            daoWithdrawRecordDao.success(req.getJSONObject("orderInfo").getString("txn_seqno"));
        } else {
            daoWithdrawRecordDao.fail(req.getJSONObject("orderInfo").getString("txn_seqno"), req.getString("failure_reason"));
        }
        return SUCCESS;
    }


    @ApiOperation(value = "连连解绑回调", notes = "连连解绑回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/unBindCardNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String unBindCardNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连解绑回调参数：{}", req);
        return SUCCESS;
    }

    @ApiOperation(value = "换绑手机号回调", notes = "换绑手机号回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/exchangePhoneNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String exchangePhoneNotify(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("换绑手机号回调：{}", req);
        LlExchangePhone llExchangePhone = llExchangePhoneDao.getBySeqNo(req.getString("txn_seqno"));
        if (ObjectUtil.isNotNull(llExchangePhone)) {
            LlUserExt llUserExt = llUserExtDao.getByUserId(llExchangePhone.getUserId());
            llUserExt.setRegPhone(llExchangePhone.getNewPhone());
            llUserExt.updateById();
            llExchangePhone.setStatus(true);
            llExchangePhone.updateById();
        }

        return SUCCESS;
    }


    @ApiOperation(value = "用户信息更新回调", notes = "用户信息更新回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/modifyUserNotifyUrl", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String modifyUserNotifyUrl(HttpServletRequest request) {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("用户信息更新回调：{}", req);
        try {
            Thread.sleep(1000);//预防事务还未提交
        } catch (Exception e) {
            e.printStackTrace();
        }
        LlModifyUserInfo modifyUserInfo = llModifyUserInfoDao.getBySeqNo(req.getString("txn_seqno"));
        if (ObjectUtil.isNull(modifyUserInfo)) {
            log.error("用户信息更新错误：未找到记录{}", req.getString("txn_seqno"));
            return SUCCESS;
        }
        if (StrUtil.equals(req.getString("stat"), "SUCCESS")) {
            modifyUserInfo.setStatus(AccountStatusEnum.SUCCESS);
            //查询用户账户等级，历史原因之前开户部分用户未上传身份证，或者等级以及账户类型不正确 导致无法使用余额支付
            LlUserExt llUserExt = llUserExtDao.getByUserId(modifyUserInfo.getUserId());
            JSONObject jsonObject = llPayHelper.queryUserInfo(llUserExt.getUserId(), llUserExt.getUserKey());
            if (!(StrUtil.equals(jsonObject.getString("account_type"), "PERSONAL_PAYMENT_ACCOUNT") && StrUtil.equals(jsonObject.getString("account_level"), "V3"))) {
                JSONObject result = llPayHelper.updateUserLevel(llUserExt.getUserId(), llUserExt.getUserKey());
                //更新成功自动处理，因老用户账户等级引起的结算失败result.getString("ret_code")
                if (ObjectUtil.isNotNull(result) && result.getString("ret_code").equals(LlPayHelper.SUCCESS_CODE)) {
                    orderSettleService.operationUserFailedSettleOrder(llUserExt.getUserId());
                }
            }
        } else {
            modifyUserInfo.setStatus(AccountStatusEnum.FAIl);
            modifyUserInfo.setRemark(req.getString("remark"));
        }
        modifyUserInfo.updateById();


        return SUCCESS;
    }


    @ApiOperation(value = "上传身份证照片", notes = "重新上传身份证照片", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/upLoadIdImage", produces = MediaType.APPLICATION_JSON_VALUE)
//    @ApiIgnore
    @WithoutSign
    @UserLogin
    public Result upLoadIdImage(@Valid @RequestBody ImageRequest request) {
        UserInfo user = UserPool.getUser();
        LlUserExt llUserExt = llUserExtDao.getByUserId(user.getId());
        if (ObjectUtil.isNull(llUserExt) || llUserExt.getStatus() != AccountStatusEnum.SUCCESS) {
            return Result.fail("未完成连连开户");
        }
        return Result.success(llPayHelper.upLoadFile(user.getId(), llUserExt.getUserKey(), LlUploadFileTypeEnum.UBO_IMAGE, request.getImage()));
    }

    @ApiOperation(value = "获取用户身份信息", notes = "获取用户身份信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getLlUserInfo", produces = MediaType.APPLICATION_JSON_VALUE)
//    @ApiIgnore
    @UserLogin
    public Result<ModifyUserInfoDTO> getLlUserInfo() {
        UserInfo user = UserPool.getUser();
        LlUserExt llUserExt = llUserExtDao.getByUserId(user.getId());
        if (ObjectUtil.isNull(llUserExt) || llUserExt.getStatus() != AccountStatusEnum.SUCCESS) {
            return Result.fail("未完成连连开户");
        }
        LlModifyUserInfo llModifyUserInfo = llModifyUserInfoDao.getLastByUserId(user.getId());
        llModifyUserInfo = ObjectUtil.isNull(llModifyUserInfo) ? llModifyUserInfo = new LlModifyUserInfo() : llModifyUserInfo;
        return Result.success(llModifyUserInfo, ModifyUserInfoDTO.class);
    }


    @ApiOperation(value = "更新身份证信息", notes = "更新身份证信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/modifyUserInfo", produces = MediaType.APPLICATION_JSON_VALUE)
//    @ApiIgnore
    @WithoutSign
    @UserLogin
    public Result modifyUserInfo(@Valid @RequestBody ModifyUserInfoDTO request) {
        UserInfo user = UserPool.getUser();
        RLock lock = redisson.getLock(RedisKeyEnum.MODIFY_USER_INFO_LOCK.getKey() + user.getId());
        boolean b = false;
        try {
            b = lock.tryLock(3, TimeUnit.SECONDS);
            if (b) {

                LlModifyUserInfo modifyUserInfo = llModifyUserInfoDao.getByUserIdAndStatus(user.getId(), AccountStatusEnum.OPENING);
                if (ObjectUtil.isNotNull(modifyUserInfo)) {
                    return Result.fail("变更申请正在审核中，请稍后再试");
                }
                llPayHelper.modifyUserInfo(user.getId(), request.getIdExp(), request.getIdStd(), request.getEmblemId(), request.getEmblemImage(), request.getPortraitId(), request.getPortraitImage(), request.getAuthorityName(), request.getAddress());
                return Result.success();
            } else {
                return Result.fail("正在提交，请稍后再试");
            }
        } catch (InterruptedException e) {
            return Result.fail("请勿重复提交");
        } finally {
            lock.unlock();
        }
    }

    @ApiOperation(value = "连连支付回调", notes = "连连支付回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/paySuccessNotifyUrl", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String paySuccessNotifyUrl(HttpServletRequest request) throws GlobalException {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连支付回调参数：{}", req);
        if (StrUtil.equals(req.getString("txn_status"), "TRADE_SUCCESS")) {
            JSONObject result = req.getJSONObject("orderInfo");
            RLock lock = redisson.getLock(RedisKeyEnum.PAY_SUCCESS_LOCK.getKey() + result.getString("txn_seqno"));
            try {
                boolean res = lock.tryLock(3, TimeUnit.SECONDS);
                if (res) {
                    payOrderService.orderPaySuccess(payOrderDao.getByTradeNo(result.getString("txn_seqno")), result.getString("txn_time"), result.toJSONString());
                    return SUCCESS;
                } else {
                    throw new GlobalException("系统繁忙");
                }
            } catch (InterruptedException e) {
                throw new GlobalException("系统超时");
            } finally {
                lock.unlock();
            }
        }
        return "FAIL";
    }

    @ApiOperation(value = "连连开户回调", notes = "连连开户回调", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/businessOpenAccountNotify", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    @WithoutSign
    public String businessOpenAccountNotify(HttpServletRequest request) throws GlobalException {
        JSONObject req = JSONObject.parseObject(new RequestWrapper(request).getBody());
        log.info("连连B端开户回调参数：{}", req);
        String seqNo = req.getString("txn_seqno");
        DaoCustomerOpenAccount account = openAccountDao.getBySeqNo(seqNo);
        if (ObjectUtil.isNull(account)) {
            log.error("未找到连连商户开户记录：{}", seqNo);
            return FAIL;
        }
        if (account.getStatus() != AccountStatusEnum.OPENING) {
            log.warn("商户不是开户中状态：{}", seqNo);
            return FAIL;
        }

        account.setRemark(req.getString("remark"));
        account.setUserStatus(req.getString("user_status"));
        account.setFinishTime(DateTime.now());
        account.setStatus(StrUtil.equals(account.getUserStatus(), "NORMAL") ? AccountStatusEnum.SUCCESS : AccountStatusEnum.FAIl);
        account.updateById();
        DaoAccountBankInfo bankInfo = bankInfoDao.getByAccountId(account.getId());
        bankInfo.setAgrtNo(req.getString("linked_agrtno"));
        bankInfo.updateById();
        return SUCCESS;
    }
}


